/*
 * @Author: 嵌入式王子
 * @Date: 2025-03-27 19:29:45
 * @LastEditors: 嵌入式王子
 * @LastEditTime: 2025-03-31 21:42:40
 * @FilePath: \mmo_check\oom_check.c
 * @Description: 开源的嵌入式软件包，本人不对此代码负责任
 *
 * 有问题可电邮 donminedm@163.com
 */

#include "oom_check.h"
#include <stdio.h>
#include <stdlib.h>

static OOM_NODE __oom_nodes[OOM_NODE_MAX];
static uint16_t __oom_node_index = 0;

static OOM_NODE *__oom_node_get(char *file_name)
{
    OOM_NODE *node = NULL;
    uint16_t i;
    // 1.查找是否已经存在节点
    for (i = 0; i < __oom_node_index; i++)
    {
        node = &__oom_nodes[i];
        if (strcmp(file_name, node->file_name) == 0)
            return node;
    }
    // 2.节点不存在，创建节点
    node = &__oom_nodes[__oom_node_index];
    memset(node, 0x00, sizeof(OOM_NODE));
    node->file_name = file_name;
    __oom_node_index++;
    return node;
}

void *
__oom_malloc(char *file_name, uint16_t row, uint16_t size)
{
    void *ptr = NULL;
    OOM_NODE *node = NULL;
    ptr = malloc(size);
    if (ptr) // 申请成功，则保存当前申请的状态
    {
        node = __oom_node_get(file_name);
        if (node->ptr_next == OOM_NODE_PTR_MAX)//超出范围释放退出
        {
            free(ptr);
            return NULL;
        }
        node->malloc_cnt += 1;
        node->use_mem += size;
        node->ptr_list[node->ptr_next].ptr = ptr;
        node->ptr_list[node->ptr_next].size = size;
        node->ptr_list[node->ptr_next].row = row;
        node->ptr_next += 1;
    }
    return ptr;
}

OOM_RES __oom_free(char *file_name, uint16_t row, void *ptr)
{
    OOM_NODE *node = NULL;
    uint16_t i;
    if (ptr == NULL)
        return OOM_NULL;
    OOM_RES res = OOM_FREE_ERR;
    node = __oom_node_get(file_name);
    for (i = 0; i < node->ptr_next; i++)
    {
        // 查找申请的内存，释放申请的节点
        if (node->ptr_list[i].ptr == (uint32_t)ptr)
        {
            node->free_cnt += 1;
            node->use_mem -= node->ptr_list[i].size;
            // 把最后一项复制到当前项覆盖，去掉最后一项
            memcpy(&node->ptr_list[i], &node->ptr_list[node->ptr_next - 1], sizeof(OOM_NODE_PTR));
            printf("%s.ptr[%d] replace ptr[%d]\r\n", file_name, node->ptr_next - 1, i);
            node->ptr_next -= 1;
            res = OOM_OK;
        }
    }
    free(ptr);
    return res;
}

void oom_printf(void)
{
    uint16_t i, j;
    uint32_t file_mem_size = 0;
    uint32_t total_mem_size = 0;
    uint32_t total_ptr_size = 0;
    OOM_NODE *node = NULL;
    printf("-------------------------------------------------------------------\r\n");
    printf("|  filename  |  size  KB  | malloc count| free count | use pointer|\r\n");
    printf("-------------------------------------------------------------------\r\n");
    for (i = 0; i < __oom_node_index; i++)
    {
        node = &__oom_nodes[i];
        file_mem_size = 0;
        for (j = 0; j < node->ptr_next; j++)
        {
            file_mem_size += node->ptr_list[j].size;
        }
        total_ptr_size += node->ptr_next;
        total_mem_size += file_mem_size;
        printf("| %10s | %10.3f | %11d | %10d | %10d |\r\n", node->file_name, (float)(file_mem_size * 1.0 / 1024), node->malloc_cnt, node->free_cnt, node->ptr_next);
    }
    printf("-------------------------------------------------------------------\r\n");
    printf("| > System use dynamic memory: %10.3f KB, pointer size: %5d |\r\n", (float)(total_mem_size * 1.0 / 1024), total_ptr_size);
    printf("-------------------------------------------------------------------\r\n\r\n");
}

uint32_t oom_node_use(const char *filename)
{
    uint16_t i, j;
    OOM_NODE *node = NULL;
    node = __oom_node_get(filename);
    return node->use_mem;
}

OOM_NODE *oom_node_get(const char *filename)
{
    return __oom_node_get(filename);
}